home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / swtools / mipsABI / examples / sup / PORT / step06 / supfilesrv.c < prev    next >
Encoding:
Text File  |  1994-08-02  |  52.7 KB  |  1,869 lines

  1. /*
  2.  * Copyright (c) 1992 Carnegie Mellon University
  3.  * All Rights Reserved.
  4.  * 
  5.  * Permission to use, copy, modify and distribute this software and its
  6.  * documentation is hereby granted, provided that both the copyright
  7.  * notice and this permission notice appear in all copies of the
  8.  * software, derivative works or modified versions, and any portions
  9.  * thereof, and that both notices appear in supporting documentation.
  10.  *
  11.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  12.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  13.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  14.  *
  15.  * Carnegie Mellon requests users of this software to return to
  16.  *
  17.  *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
  18.  *  School of Computer Science
  19.  *  Carnegie Mellon University
  20.  *  Pittsburgh PA 15213-3890
  21.  *
  22.  * any improvements or extensions that they make and grant Carnegie Mellon
  23.  * the rights to redistribute these changes.
  24.  *
  25. /*
  26.  * supfilesrv -- SUP File Server
  27.  *
  28.  * Usage:  supfilesrv [-l] [-P] [-N] [-R]
  29.  *    -l    "live" -- don't fork daemon
  30.  *    -P    "debug ports" -- use debugging network ports
  31.  *    -N    "debug network" -- print debugging messages for network i/o
  32.  *    -R    "RCS mode" -- if file is an rcs file, use co to get contents
  33.  *
  34.  **********************************************************************
  35.  * HISTORY
  36.  * 13-Sep-92  Mary Thompson (mrt) at Carnegie-Mellon University
  37.  *    Changed name of sup program in xpatch from /usr/cs/bin/sup to
  38.  *    /usr/bin/sup for exported version of sup.
  39.  *
  40.  * 7-July-93  Nate Williams at Montana State University
  41.  *    Modified SUP to use gzip based compression when sending files
  42.  *    across the network to save BandWidth
  43.  *
  44.  * $Log: supfilesrv.c,v $
  45.  * Revision 1.5  1993/08/04  17:46:21  brezak
  46.  * Changes from nate for gzip'ed sup
  47.  *
  48.  * Revision 1.3  1993/06/05  21:32:17  cgd
  49.  * use daemon() to put supfilesrv into daemon mode...
  50.  *
  51.  * Revision 1.2  1993/05/24  17:57:31  brezak
  52.  * Remove netcrypt.c. Remove unneeded files. Cleanup make.
  53.  *
  54.  * Revision 1.20  92/09/09  22:05:00  mrt
  55.  *     Added Brad's change to make sendfile take a va_list.
  56.  *     Added support in login to accept an non-encrypted login
  57.  *     message if no user or password is being sent. This supports
  58.  *     a non-crypting version of sup. Also fixed to skip leading
  59.  *     white space from crypts in host files.
  60.  *     [92/09/01            mrt]
  61.  * 
  62.  * Revision 1.19  92/08/11  12:07:59  mrt
  63.  *         Made maxchildren a patchable variable, which can be set by the
  64.  *         command line switch -C or else defaults to the MAXCHILDREN
  65.  *         defined in sup.h. Added most of Brad's STUMP changes.
  66.  *     Increased PGMVERSION to 12 to reflect substantial changes.
  67.  *     [92/07/28            mrt]
  68.  * 
  69.  * Revision 1.18  90/12/25  15:15:39  ern
  70.  *     Yet another rewrite of the logging code. Make up the text we will write
  71.  *        and then get in, write it and get out.
  72.  *     Also set error on write-to-full-disk if the logging is for recording
  73.  *        server is busy.
  74.  *     [90/12/25  15:15:15  ern]
  75.  * 
  76.  * Revision 1.17  90/05/07  09:31:13  dlc
  77.  *     Sigh, some more fixes to the new "crypt" file handling code.  First,
  78.  *     just because the "crypt" file is in a local file system does not mean
  79.  *     it can be trusted.  We have to check for hard links to root owned
  80.  *     files whose contents could be interpretted as a crypt key.  For
  81.  *     checking this fact, the new routine stat_info_ok() was added.  This
  82.  *     routine also makes other sanity checks, such as owner only permission,
  83.  *     the file is a regular file, etc.  Also, even if the uid/gid of th
  84.  *     "crypt" file is not going to be used, still use its contents in order
  85.  *     to cause fewer surprises to people supping out of a shared file system
  86.  *     such as AFS.
  87.  *     [90/05/07            dlc]
  88.  * 
  89.  * Revision 1.16  90/04/29  04:21:08  dlc
  90.  *     Fixed logic bug in docrypt() which would not get the stat information
  91.  *     from the crypt file if the crypt key had already been set from a
  92.  *     "host" file.
  93.  *     [90/04/29            dlc]
  94.  * 
  95.  * Revision 1.15  90/04/18  19:51:27  dlc
  96.  *     Added the new routines local_file(), link_nofollow() for use in
  97.  *     dectecting whether a file is located in a local file system.  These
  98.  *     routines probably should have been in another module, but only
  99.  *     supfilesrv needs to do the check and none of its other modules seemed
  100.  *     appropriate.  Note, the implementation should be changed once we have
  101.  *     direct kernel support, for example the fstatfs(2) system call, for
  102.  *     detecting the type of file system a file resides.  Also, I changed
  103.  *     the routines which read the crosspatch crypt file or collection crypt
  104.  *     file to save the uid and gid from the stat information obtained via
  105.  *     the local_file() call (when the file is local) at the same time the
  106.  *     crypt key is read.  This change disallows non-local files for the
  107.  *     crypt key to plug a security hole involving the usage of the uid/gid
  108.  *     of the crypt file to define who the the file server should run as.  If
  109.  *     the saved uid/gid are both valid, then the server will set its uid/gid
  110.  *     to these values.
  111.  *     [90/04/18            dlc]
  112.  * 
  113.  * Revision 1.14  89/08/23  14:56:15  gm0w
  114.  *     Changed msgf routines to msg routines.
  115.  *     [89/08/23            gm0w]
  116.  * 
  117.  * Revision 1.13  89/08/03  19:57:33  mja
  118.  *     Remove setaid() call.
  119.  * 
  120.  * Revision 1.12  89/08/03  19:49:24  mja
  121.  *     Updated to use v*printf() in place of _doprnt().
  122.  *     [89/04/19            mja]
  123.  * 
  124.  * 11-Sep-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  125.  *    Added code to record release name in logfile.
  126.  *
  127.  * 18-Mar-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  128.  *    Added host=<hostfile> support to releases file. [V7.12]
  129.  *
  130.  * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  131.  *    Added crosspatch support.  Created docrypt() routine for crypt
  132.  *    test message.
  133.  *
  134.  * 09-Sep-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  135.  *    Removed common information logging code, the quiet switch, and
  136.  *    moved samehost() check to after device/inode check.
  137.  *
  138.  * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  139.  *    Added code for "release" support. [V5.11]
  140.  *
  141.  * 26-May-87  Doug Philips (dwp) at Carnegie-Mellon University
  142.  *    Added code to record final status of client in logfile. [V5.10]
  143.  *
  144.  * 22-May-87  Chriss Stephens (chriss) at Carnegie Mellon University
  145.  *    Mergered divergent CS and ECE versions. [V5.9a]
  146.  *
  147.  * 20-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  148.  *    Removed support for version 3 of SUP protocol.  Added changes
  149.  *    to make lint happy.  Added calls to new logging routines. [V5.9]
  150.  *
  151.  * 31-Mar-87  Dan Nydick (dan) at Carnegie-Mellon University
  152.  *    Fixed so no password check is done when crypts are used.
  153.  *
  154.  * 25-Nov-86  Rudy Nedved (ern) at Carnegie-Mellon University
  155.  *    Set F_APPEND fcntl in logging to increase the chance
  156.  *    that the log entry from this incarnation of the file
  157.  *    server will not be lost by another incarnation. [V5.8]
  158.  *
  159.  * 20-Oct-86  Dan Nydick (dan) at Carnegie-Mellon University
  160.  *    Changed not to call okmumbles when not compiled with CMUCS.
  161.  *
  162.  * 04-Aug-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  163.  *    Added code to increment scmdebug as more -N flags are
  164.  *    added. [V5.7]
  165.  *
  166.  * 25-May-86  Jonathan J. Chew (jjc) at Carnegie-Mellon University
  167.  *    Renamed local variable in main program from "sigmask" to
  168.  *    "signalmask" to avoid name conflict with 4.3BSD identifier.
  169.  *    Conditionally compile in calls to CMU routines, "setaid" and
  170.  *    "logaccess". [V5.6]
  171.  *
  172.  * 21-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  173.  *    Changed supfilesrv to use the crypt file owner and group for
  174.  *    access purposes, rather than the directory containing the crypt
  175.  *    file. [V5.5]
  176.  *
  177.  * 07-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  178.  *    Added code to keep logfiles in repository collection directory.
  179.  *    Added code for locking collections. [V5.4]
  180.  *
  181.  * 05-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  182.  *    Added code to support new FSETUPBUSY return.  Now accepts all
  183.  *    connections and tells any clients after the 8th that the
  184.  *    fileserver is busy.  New clients will retry again later. [V5.3]
  185.  *
  186.  * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  187.  *    Major rewrite for protocol version 4. [V4.2]
  188.  *
  189.  * 12-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  190.  *    Fixed close of crypt file to use file pointer as argument
  191.  *    instead of string pointer.
  192.  *
  193.  * 24-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  194.  *    Allow "!hostname" lines and comments in collection "host" file.
  195.  *
  196.  * 13-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  197.  *    Don't use access() on symbolic links since they may not point to
  198.  *    an existing file.
  199.  *
  200.  * 22-Oct-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  201.  *    Added code to restrict file server availability to when it has
  202.  *    less than or equal to eight children.
  203.  *
  204.  * 22-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  205.  *    Merged 4.1 and 4.2 versions together.
  206.  *
  207.  * 04-Jun-85  Steven Shafer (sas) at Carnegie-Mellon University
  208.  *    Created for 4.2 BSD.
  209.  *
  210.  **********************************************************************
  211.  */
  212.  
  213. #include <libc.h>
  214. #ifdef AFS
  215. #include <afs/param.h>
  216. #undef MAXNAMLEN
  217. #endif
  218. #include <sys/param.h>
  219. #include <c.h>
  220. #include <signal.h>
  221. #include <errno.h>
  222. #include <setjmp.h>
  223. #include <pwd.h>
  224. #include <grp.h>
  225. #if __STDC__
  226. #include <stdarg.h>
  227. #else
  228. #include <varargs.h>
  229. #endif
  230. #include <sys/time.h>
  231. #include <sys/resource.h>
  232. #include <sys/wait.h>
  233. #include <sys/stat.h>
  234. #include <sys/file.h>
  235. #include <sys/dir.h>
  236. #if    MACH
  237. #include <sys/ioctl.h>
  238. #endif
  239. #if    CMUCS
  240. #include <acc.h>
  241. #include <sys/ttyloc.h>
  242. #include <access.h>
  243. #include <sys/viceioctl.h>
  244. #else    CMUCS
  245. #define ACCESS_CODE_OK        0
  246. #define ACCESS_CODE_BADPASSWORD (-2)
  247. #endif  CMUCS
  248. #include "sup.h"
  249. #define MSGFILE
  250. #include "supmsg.h"
  251.  
  252. #ifdef    lint
  253. /*VARARGS1*//*ARGSUSED*/
  254. static void quit(status) {};
  255. #endif    /* lint */
  256.  
  257. #if __STDC__
  258. void goaway (char *,...);
  259. #endif
  260.  
  261. extern int errno;
  262. long time ();
  263. uid_t getuid ();
  264.  
  265. int maxchildren;
  266.  
  267. /*
  268.  * These are used to save the stat information from the crosspatch crypt
  269.  * file or collection crypt file at the time it is opened for the crypt
  270.  * key and it is verified to be a local file.
  271.  */
  272. int runas_uid = -1;
  273. int runas_gid = -1;
  274.  
  275. #define PGMVERSION 13
  276.  
  277. /*************************
  278.  ***    M A C R O S    ***
  279.  *************************/
  280.  
  281. #define HASHBITS 8
  282. #define HASHSIZE (1<<HASHBITS)
  283. #define HASHMASK (HASHSIZE-1)
  284. #define HASHFUNC(x,y) ((x)&HASHMASK)
  285.  
  286. /*******************************************
  287.  ***    D A T A   S T R U C T U R E S    ***
  288.  *******************************************/
  289.  
  290. struct hashstruct {            /* hash table for number lists */
  291.     int Hnum1;            /* numeric keys */
  292.     int Hnum2;
  293.     char *Hname;            /* string value */
  294.     TREE *Htree;            /* TREE value */
  295.     struct hashstruct *Hnext;
  296. };
  297. typedef struct hashstruct HASH;
  298.  
  299. /*********************************************
  300.  ***    G L O B A L   V A R I A B L E S    ***
  301.  *********************************************/
  302.  
  303. char program[] = "supfilesrv";        /* program name for SCM messages */
  304. int progpid = -1;            /* and process id */
  305.  
  306. jmp_buf sjbuf;                /* jump location for network errors */
  307. TREELIST *listTL;            /* list of trees to upgrade */
  308.  
  309. int live;                /* -l flag */
  310. int dbgportsq;                /* -P flag */
  311. extern int scmdebug;            /* -N flag */
  312. extern int netfile;
  313. #ifdef RCS
  314. int candorcs;                /* -R flag */
  315. int dorcs = FALSE;
  316. #endif
  317.  
  318. char *clienthost;            /* host name of client */
  319. int nchildren;                /* number of children that exist */
  320. char *prefix;                /* collection pathname prefix */
  321. char *release;                /* collection release name */
  322. char *cryptkey;                /* encryption key if non-null */
  323. #ifdef CVS
  324. char *cvs_root;                /* RCS root */
  325. #endif
  326. char *rcs_branch;            /* RCS branch name */
  327. int lockfd;                /* descriptor of lock file */
  328.  
  329. /* global variables for scan functions */
  330. int trace = FALSE;            /* directory scan trace */
  331. int cancompress = FALSE;        /* Can we compress files */
  332. int docompress = FALSE;            /* Do we compress files */
  333.  
  334. HASH *uidH[HASHSIZE];            /* for uid and gid lookup */
  335. HASH *gidH[HASHSIZE];
  336. HASH *inodeH[HASHSIZE];            /* for inode lookup for linked file check */
  337.  
  338. char *fmttime ();            /* time format routine */
  339.  
  340. /*************************************
  341.  ***    M A I N   R O U T I N E    ***
  342.  *************************************/
  343.  
  344. main (argc,argv)
  345. int argc;
  346. char **argv;
  347. {
  348. #ifdef _ABI_SOURCE
  349.     register int x,pid;
  350.     sigset_t signalmask, oldsignalmask;
  351.     struct sigaction chldvec,ignvec,oldvec;
  352. #else
  353.     register int x,pid,signalmask;
  354.     struct sigvec chldvec,ignvec,oldvec;
  355. #endif
  356.     int chldsig ();
  357.     long tloc;
  358.  
  359.     /* initialize global variables */
  360.     pgmversion = PGMVERSION;    /* export version number */
  361.     server = TRUE;            /* export that we're not a server */
  362.     collname = NULL;        /* no current collection yet */
  363.     maxchildren = MAXCHILDREN;    /* defined in sup.h */
  364.  
  365.     init (argc,argv);        /* process arguments */
  366.  
  367. #ifdef HAS_DAEMON
  368.     if (!live)            /* if not debugging, turn into daemon */
  369.         daemon(0, 0);
  370. #endif
  371.  
  372.     logopen ("supfile");
  373.     tloc = time ((long *)NULL);
  374.     loginfo ("SUP File Server Version %d.%d (%s) starting at %s",
  375.         PROTOVERSION,PGMVERSION,scmversion,fmttime (tloc));
  376.     if (live) {
  377.         x = service ();
  378.         if (x != SCMOK)
  379.             logquit (1,"Can't connect to network");
  380.         answer ();
  381.         (void) serviceend ();
  382.         exit (0);
  383.     }
  384. #ifdef _ABI_SOURCE
  385.     ignvec.sa_handler = SIG_IGN;
  386.     sigemptyset (&(ignvec.sa_mask));
  387.     ignvec.sa_flags = 0;
  388.     (void) sigaction (SIGHUP,&ignvec,&oldvec);
  389.     (void) sigaction (SIGINT,&ignvec,&oldvec);
  390.     (void) sigaction (SIGPIPE,&ignvec,&oldvec);
  391.     chldvec.sa_handler = chldsig;
  392.     sigemptyset (&(chldvec.sa_mask));
  393.     chldvec.sa_flags = 0;
  394.     (void) sigaction (SIGCHLD,&chldvec,&oldvec);
  395. #else
  396.     ignvec.sv_handler = SIG_IGN;
  397.     ignvec.sv_onstack = 0;
  398.     ignvec.sv_mask = 0;
  399.     (void) sigvec (SIGHUP,&ignvec,&oldvec);
  400.     (void) sigvec (SIGINT,&ignvec,&oldvec);
  401.     (void) sigvec (SIGPIPE,&ignvec,&oldvec);
  402.     chldvec.sv_handler = chldsig;
  403.     chldvec.sv_mask = 0;
  404.     chldvec.sv_onstack = 0;
  405.     (void) sigvec (SIGCHLD,&chldvec,&oldvec);
  406. #endif
  407.     nchildren = 0;
  408.     for (;;) {
  409.         x = service ();
  410.         if (x != SCMOK) {
  411.             logerr ("Error in establishing network connection");
  412.             (void) servicekill ();
  413.             continue;
  414.         }
  415. #ifdef _ABI_SOURCE
  416.         sigemptyset (&signalmask);
  417.         sigaddset (&signalmask, SIGCHLD);
  418.         (void) sigprocmask (SIG_BLOCK, &signalmask, &oldsignalmask);
  419. #else
  420.         signalmask = sigblock(sigmask(SIGCHLD));
  421. #endif
  422.         if ((pid = fork()) == 0) { /* server process */
  423.             (void) serviceprep ();
  424.             answer ();
  425.             (void) serviceend ();
  426.             exit (0);
  427.         }
  428.         (void) servicekill ();    /* parent */
  429.         if (pid > 0) nchildren++;
  430. #ifdef _ABI_SOURCE
  431.         (void) sigprocmask (SIG_SETMASK, &oldsignalmask, NULL);
  432. #else
  433.         (void) sigsetmask(signalmask);
  434. #endif
  435.     }
  436. }
  437.  
  438. /*
  439.  * Child status signal handler
  440.  */
  441.  
  442. chldsig()
  443. {
  444.     union wait w;
  445.  
  446.     /* XXX all the signal stuff needs attention */
  447.     while (wait3(&w, WNOHANG, (struct rusage *)0) > 0) {
  448.         if (nchildren) nchildren--;
  449.     }
  450. }
  451.  
  452. /*****************************************
  453.  ***    I N I T I A L I Z A T I O N    ***
  454.  *****************************************/
  455.  
  456. usage ()
  457. {
  458.     quit (1,"Usage: supfilesrv [ -l | -P | -N | -C <max children> | -H <host> <user> <cryptfile> <supargs> ]\n");
  459. }
  460.  
  461. init (argc,argv)
  462. int argc;
  463. char **argv;
  464. {
  465.     register int i;
  466.     register int x;
  467.     char *clienthost,*clientuser;
  468.     char *p,*q;
  469.     char buf[STRINGLENGTH];
  470.     int maxsleep;
  471.     register FILE *f;
  472.  
  473. #ifdef RCS
  474.         candorcs = FALSE;
  475. #endif
  476.     live = FALSE;
  477.     dbgportsq = FALSE;
  478.     scmdebug = 0;
  479.     clienthost = NULL;
  480.     clientuser = NULL;
  481.     maxsleep = 5;
  482.     if (--argc < 0)
  483.         usage ();
  484.     argv++;
  485.     while (clienthost == NULL && argc > 0 && argv[0][0] == '-') {
  486.         switch (argv[0][1]) {
  487.         case 'l':
  488.             live = TRUE;
  489.             break;
  490.         case 'P':
  491.             dbgportsq = TRUE;
  492.             break;
  493.         case 'N':
  494.             scmdebug++;
  495.             break;
  496.         case 'C':
  497.             if (--argc < 1)
  498.                 quit (1,"Missing arg to -C\n");
  499.             argv++;
  500.             maxchildren = atoi(argv[0]);
  501.             break;
  502.         case 'H':
  503.             if (--argc < 3)
  504.                 quit (1,"Missing args to -H\n");
  505.             argv++;
  506.             clienthost = argv[0];
  507.             clientuser = argv[1];
  508.             cryptkey = argv[2];
  509.             argc -= 2;
  510.             argv += 2;
  511.             break;
  512. #ifdef RCS
  513.                 case 'R':
  514.                         candorcs = TRUE;
  515.                         break;
  516. #endif
  517.         default:
  518.             fprintf (stderr,"Unknown flag %s ignored\n",argv[0]);
  519.             break;
  520.         }
  521.         --argc;
  522.         argv++;
  523.     }
  524.     if (clienthost == NULL) {
  525.         if (argc != 0)
  526.             usage ();
  527.         x = servicesetup (dbgportsq ? DEBUGFPORT : FILEPORT);
  528.         if (x != SCMOK)
  529.             quit (1,"Error in network setup");
  530.         for (i = 0; i < HASHSIZE; i++)
  531.             uidH[i] = gidH[i] = inodeH[i] = NULL;
  532.         return;
  533.     }
  534.     server = FALSE;
  535.     if (argc < 1)
  536.         usage ();
  537.     f = fopen (cryptkey,"r");
  538.     if (f == NULL)
  539.         quit (1,"Unable to open cryptfile %s\n",cryptkey);
  540.     if (p = fgets (buf,STRINGLENGTH,f)) {
  541.         if (q = index (p,'\n'))  *q = '\0';
  542.         if (*p == '\0')
  543.             quit (1,"No cryptkey found in %s\n",cryptkey);
  544.         cryptkey = salloc (buf);
  545.     }
  546.     (void) fclose (f);
  547.     x = request (dbgportsq ? DEBUGFPORT : FILEPORT,clienthost,&maxsleep);
  548.     if (x != SCMOK)
  549.         quit (1,"Unable to connect to host %s\n",clienthost);
  550.     x = msgsignon ();
  551.     if (x != SCMOK)
  552.         quit (1,"Error sending signon request to fileserver\n");
  553.     x = msgsignonack ();
  554.     if (x != SCMOK)
  555.         quit (1,"Error reading signon reply from fileserver\n");
  556.     printf ("SUP Fileserver %d.%d (%s) %d on %s\n",
  557.         protver,pgmver,scmver,fspid,remotehost());
  558.     free (scmver);
  559.     scmver = NULL;
  560.     if (protver < 7)
  561.         quit (1,"Remote fileserver does not implement reverse sup\n");
  562.     xpatch = TRUE;
  563.     xuser = clientuser;
  564.     x = msgsetup ();
  565.     if (x != SCMOK)
  566.         quit (1,"Error sending setup request to fileserver\n");
  567.     x = msgsetupack ();
  568.     if (x != SCMOK)
  569.         quit (1,"Error reading setup reply from fileserver\n");
  570.     switch (setupack) {
  571.     case FSETUPOK:
  572.         break;
  573.     case FSETUPSAME:
  574.         quit (1,"User %s not found on remote client\n",xuser);
  575.     case FSETUPHOST:
  576.         quit (1,"This host has no permission to reverse sup\n");
  577.     default:
  578.         quit (1,"Unrecognized file server setup status %d\n",setupack);
  579.     }
  580.     if (netcrypt (cryptkey) != SCMOK )
  581.         quit (1,"Running non-crypting fileserver\n");
  582.     crypttest = CRYPTTEST;
  583.     x = msgcrypt ();
  584.     if (x != SCMOK)
  585.         quit (1,"Error sending encryption test request\n");
  586.     x = msgcryptok ();
  587.     if (x == SCMEOF)
  588.         quit (1,"Data encryption test failed\n");
  589.     if (x != SCMOK)
  590.         quit (1,"Error reading encryption test reply\n");
  591.     logcrypt = CRYPTTEST;
  592.     loguser = NULL;
  593.     logpswd = NULL;
  594.     if (netcrypt (PSWDCRYPT) != SCMOK)    /* encrypt password data */
  595.         quit (1,"Running non-crypting fileserver\n");
  596.     x = msglogin ();
  597.     (void) netcrypt ((char *)NULL);    /* turn off encryption */
  598.     if (x != SCMOK)
  599.         quit (1,"Error sending login request to file server\n");
  600.     x = msglogack ();
  601.     if (x != SCMOK)
  602.         quit (1,"Error reading login reply from file server\n");
  603.     if (logack == FLOGNG)
  604.         quit (1,"%s\nImproper login to %s account\n",logerror,xuser);
  605.     xargc = argc;
  606.     xargv = argv;
  607.     x = msgxpatch ();
  608.     if (x != SCMOK)
  609.         quit (1,"Error sending crosspatch request\n");
  610.         crosspatch ();
  611.     exit (0);
  612. }
  613.  
  614. /*****************************************
  615.  ***    A N S W E R   R E Q U E S T    ***
  616.  *****************************************/
  617.  
  618. answer ()
  619. {
  620.     long starttime;
  621.     register int x;
  622. #ifdef _ABI_SOURCE
  623.     struct rlimit rl;
  624. #endif
  625.  
  626.     progpid = fspid = getpid ();
  627.     collname = NULL;
  628.     basedir = NULL;
  629.     prefix = NULL;
  630.     release = NULL;
  631.         rcs_branch = NULL;
  632. #ifdef CVS
  633.         cvs_root = NULL;
  634. #endif
  635.     goawayreason = NULL;
  636.     donereason = NULL;
  637.     lockfd = -1;
  638.     starttime = time ((long *)NULL);
  639.     if (!setjmp (sjbuf)) {
  640.         signon ();
  641.         setup ();
  642.         docrypt ();
  643.         login ();
  644.         if (xpatch) {
  645.             int fd;
  646.  
  647.             x = msgxpatch ();
  648.             if (x != SCMOK)
  649.                 exit (0);
  650.             xargv[0] = "sup";
  651.             xargv[1] = "-X";
  652.             xargv[xargc] = (char *)NULL;
  653.             (void) dup2 (netfile,0);
  654.             (void) dup2 (netfile,1);
  655.             (void) dup2 (netfile,2);
  656. #ifdef _ABI_SOURCE
  657.             getrlimit (RLIMIT_NOFILE, &rl);
  658.             fd = rl.rlim_max;
  659. #else
  660.             fd = getdtablesize ();
  661. #endif
  662.             while (--fd > 2)
  663.                 (void) close (fd);
  664.             execvp (xargv[0],xargv);
  665.             exit (0);
  666.         }
  667.         listfiles ();
  668.         sendfiles ();
  669.     }
  670.     finishup (starttime);
  671.     if (collname)  free (collname);
  672.     if (basedir)  free (basedir);
  673.     if (prefix)  free (prefix);
  674.     if (release)  free (release);
  675.     if (rcs_branch)  free (rcs_branch);
  676. #ifdef CVS
  677.     if (cvs_root)  free (cvs_root);
  678. #endif
  679.     if (goawayreason) {
  680.         if (donereason == goawayreason)
  681.             donereason = NULL;
  682.         free (goawayreason);
  683.     }
  684.     if (donereason)  free (donereason);
  685.     if (lockfd >= 0)  (void) close (lockfd);
  686.     endpwent ();
  687.     (void) endgrent ();
  688. #if    CMUCS
  689.     endacent ();
  690. #endif    /* CMUCS */
  691.     Hfree (uidH);
  692.     Hfree (gidH);
  693.     Hfree (inodeH);
  694. }
  695.  
  696. /*****************************************
  697.  ***    S I G N   O N   C L I E N T    ***
  698.  *****************************************/
  699.  
  700. signon ()
  701. {
  702.     register int x;
  703.  
  704.     xpatch = FALSE;
  705.     x = msgsignon ();
  706.     if (x != SCMOK)  goaway ("Error reading signon request from client");
  707.     x = msgsignonack ();
  708.     if (x != SCMOK)  goaway ("Error sending signon reply to client");
  709.     free (scmver);
  710.     scmver = NULL;
  711. }
  712.  
  713. /*****************************************************************
  714.  ***    E X C H A N G E   S E T U P   I N F O R M A T I O N    ***
  715.  *****************************************************************/
  716.  
  717. setup ()
  718. {
  719.     register int x;
  720.     char *p,*q;
  721.     char buf[STRINGLENGTH];
  722.     register FILE *f;
  723.     struct stat sbuf;
  724.     register TREELIST *tl;
  725.  
  726.     if (protver > 7) {
  727.         cancompress = TRUE;
  728.     }
  729.     x = msgsetup ();
  730.     if (x != SCMOK)  goaway ("Error reading setup request from client");
  731.     if (protver < 4) {
  732.         setupack = FSETUPOLD;
  733.         (void) msgsetupack ();
  734.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  735.         goaway ("Sup client using obsolete version of protocol");
  736.     }
  737.     if (xpatch) {
  738.         register struct passwd *pw;
  739.         extern int link_nofollow(), local_file();
  740.  
  741.         if ((pw = getpwnam (xuser)) == NULL) {
  742.             setupack = FSETUPSAME;
  743.             (void) msgsetupack ();
  744.             if (protver >= 6)  longjmp (sjbuf,TRUE);
  745.             goaway ("User not found");
  746.         }
  747.         (void) free (xuser);
  748.         xuser = salloc (pw->pw_dir);
  749.  
  750.         /* check crosspatch host access file */
  751.         cryptkey = NULL;
  752.         (void) sprintf (buf,FILEXPATCH,xuser);
  753.  
  754.         /* Turn off link following */
  755.         if (link_nofollow(1) != -1) {
  756.             int hostok = FALSE;
  757.             /* get stat info before open */
  758.             if (stat(buf, &sbuf) == -1)
  759.                 (void) bzero((char *)&sbuf, sizeof(sbuf));
  760.  
  761.             if ((f = fopen (buf,"r")) != NULL) {
  762.                 struct stat fsbuf;
  763.  
  764.                 while (p = fgets (buf,STRINGLENGTH,f)) {
  765.                     q = index (p,'\n');
  766.                     if (q)  *q = 0;
  767.                     if (index ("#;:",*p))  continue;
  768.                     q = nxtarg (&p," \t");
  769.                     if (*p == '\0')  continue;
  770.                     if (!matchhost(q)) continue;
  771.  
  772.                     cryptkey = salloc (p);
  773.                     hostok = TRUE;
  774.                     if (local_file(fileno(f), &fsbuf) > 0
  775.                         && stat_info_ok(&sbuf, &fsbuf)) {
  776.                         runas_uid = sbuf.st_uid;
  777.                         runas_gid = sbuf.st_gid;
  778.                     }
  779.                     break;
  780.                 }
  781.                 (void) fclose (f);
  782.             }
  783.  
  784.             /* Restore link following */
  785.             if (link_nofollow(0) == -1)
  786.                 goaway ("Restore link following");
  787.  
  788.             if (!hostok) {
  789.                 setupack = FSETUPHOST;
  790.                 (void) msgsetupack ();
  791.                 if (protver >= 6)  longjmp (sjbuf,TRUE);
  792.                 goaway ("Host not on access list");
  793.             }
  794.         }
  795.         setupack = FSETUPOK;
  796.         x = msgsetupack ();
  797.         if (x != SCMOK)
  798.             goaway ("Error sending setup reply to client");
  799.         return;
  800.     }
  801. #ifdef RCS
  802.         if (candorcs && release != NULL &&
  803.             (strncmp(release, "RCS.", 4) == 0)) {
  804.                 rcs_branch = salloc(&release[4]);
  805.                 free(release);
  806.                 release = salloc("RCS");
  807.                 dorcs = TRUE;
  808.         }
  809. #endif
  810.     if (release == NULL)
  811.         release = salloc (DEFRELEASE);
  812.     if (basedir == NULL || *basedir == '\0') {
  813.         basedir = NULL;
  814.         (void) sprintf (buf,FILEDIRS,DEFDIR);
  815.         f = fopen (buf,"r");
  816.         if (f) {
  817.             while (p = fgets (buf,STRINGLENGTH,f)) {
  818.                 q = index (p,'\n');
  819.                 if (q)  *q = 0;
  820.                 if (index ("#;:",*p))  continue;
  821.                 q = nxtarg (&p," \t=");
  822.                 if (strcmp(q,collname) == 0) {
  823.                     basedir = skipover(p," \t=");
  824.                     basedir = salloc (basedir);
  825.                     break;
  826.                 }
  827.             }
  828.             (void) fclose (f);
  829.         }
  830.         if (basedir == NULL) {
  831.             (void) sprintf (buf,FILEBASEDEFAULT,collname);
  832.             basedir = salloc(buf);
  833.         }
  834.     }
  835.     if (chdir (basedir) < 0)
  836.         goaway ("Can't chdir to base directory %s",basedir);
  837.     (void) sprintf (buf,FILEPREFIX,collname);
  838.     f = fopen (buf,"r");
  839.     if (f) {
  840.         while (p = fgets (buf,STRINGLENGTH,f)) {
  841.             q = index (p,'\n');
  842.             if (q)  *q = 0;
  843.             if (index ("#;:",*p))  continue;
  844.             prefix = salloc(p);
  845.             if (chdir (prefix) < 0)
  846.                 goaway ("Can't chdir to %s from base directory %s",
  847.                     prefix,basedir);
  848.             break;
  849.         }
  850.         (void) fclose (f);
  851.     }
  852.     x = stat (".",&sbuf);
  853.     if (prefix)  (void) chdir (basedir);
  854.     if (x < 0)
  855.         goaway ("Can't stat base/prefix directory");
  856.     if (nchildren >= maxchildren) {
  857.         setupack = FSETUPBUSY;
  858.         (void) msgsetupack ();
  859.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  860.         goaway ("Sup client told to try again later");
  861.     }
  862.     if (sbuf.st_dev == basedev && sbuf.st_ino == baseino && samehost()) {
  863.         setupack = FSETUPSAME;
  864.         (void) msgsetupack ();
  865.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  866.         goaway ("Attempt to upgrade to same directory on same host");
  867.     }
  868.     /* obtain release information */
  869.     if (!getrelease (release)) {
  870.         setupack = FSETUPRELEASE;
  871.         (void) msgsetupack ();
  872.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  873.         goaway ("Invalid release information");
  874.     }
  875.     /* check host access file */
  876.     cryptkey = NULL;
  877.     for (tl = listTL; tl != NULL; tl = tl->TLnext) {
  878.         char *h;
  879.         if ((h = tl->TLhost) == NULL)
  880.             h = FILEHOSTDEF;
  881.         (void) sprintf (buf,FILEHOST,collname,h);
  882.         f = fopen (buf,"r");
  883.         if (f) {
  884.             int hostok = FALSE;
  885.             while (p = fgets (buf,STRINGLENGTH,f)) {
  886.                 int not;
  887.                 q = index (p,'\n');
  888.                 if (q)  *q = 0;
  889.                 if (index ("#;:",*p))  continue;
  890.                 q = nxtarg (&p," \t");
  891.                 if ((not = (*q == '!')) && *++q == '\0')
  892.                     q = nxtarg (&p," \t");
  893.                 hostok = (not == (matchhost(q) == 0));
  894.                 if (hostok) {
  895.                     while ((*p == ' ') || (*p == '\t')) p++;
  896.                     if (*p)  cryptkey = salloc (p);
  897.                     break;
  898.                 }
  899.             }
  900.             (void) fclose (f);
  901.             if (!hostok) {
  902.                 setupack = FSETUPHOST;
  903.                 (void) msgsetupack ();
  904.                 if (protver >= 6)  longjmp (sjbuf,TRUE);
  905.                 goaway ("Host not on access list for %s",
  906.                     collname);
  907.             }
  908.         }
  909.     }
  910.     /* try to lock collection */
  911.     (void) sprintf (buf,FILELOCK,collname);
  912.     x = open (buf,O_RDONLY,0);
  913.     if (x >= 0) {
  914.         if (flock (x,(LOCK_SH|LOCK_NB)) < 0) {
  915.             (void) close (x);
  916.             if (errno != EWOULDBLOCK)
  917.                 goaway ("Can't lock collection %s",collname);
  918.             setupack = FSETUPBUSY;
  919.             (void) msgsetupack ();
  920.             if (protver >= 6)  longjmp (sjbuf,TRUE);
  921.             goaway ("Sup client told to wait for lock");
  922.         }
  923.         lockfd = x;
  924.     }
  925.     setupack = FSETUPOK;
  926.     x = msgsetupack ();
  927.     if (x != SCMOK)  goaway ("Error sending setup reply to client");
  928. }
  929.  
  930. /** Test data encryption **/
  931. docrypt ()
  932. {
  933.     register int x;
  934.     char *p,*q;
  935.     char buf[STRINGLENGTH];
  936.     register FILE *f;
  937.     struct stat sbuf;
  938.     extern int  link_nofollow(), local_file();
  939.  
  940.     if (!xpatch) {
  941.         (void) sprintf (buf,FILECRYPT,collname);
  942.  
  943.         /* Turn off link following */
  944.         if (link_nofollow(1) != -1) {
  945.             /* get stat info before open */
  946.             if (stat(buf, &sbuf) == -1)
  947.                 (void) bzero((char *)&sbuf, sizeof(sbuf));
  948.  
  949.             if ((f = fopen (buf,"r")) != NULL) {
  950.                 struct stat fsbuf;
  951.  
  952.                 if (cryptkey == NULL &&
  953.                     (p = fgets (buf,STRINGLENGTH,f))) {
  954.                     if (q = index (p,'\n'))  *q = '\0';
  955.                     if (*p)  cryptkey = salloc (buf);
  956.                 }
  957.                 if (local_file(fileno(f), &fsbuf) > 0
  958.                     && stat_info_ok(&sbuf, &fsbuf)) {
  959.                     runas_uid = sbuf.st_uid;
  960.                     runas_gid = sbuf.st_gid;
  961.                 }
  962.                 (void) fclose (f);
  963.             }
  964.             /* Restore link following */
  965.             if (link_nofollow(0) == -1)
  966.                 goaway ("Restore link following");
  967.         }
  968.     }
  969.     if ( netcrypt (cryptkey) != SCMOK )
  970.         goaway ("Runing non-crypting supfilesrv");
  971.     x = msgcrypt ();
  972.     if (x != SCMOK)
  973.         goaway ("Error reading encryption test request from client");
  974.     (void) netcrypt ((char *)NULL);
  975.     if (strcmp(crypttest,CRYPTTEST) != 0)
  976.         goaway ("Client not encrypting data properly");
  977.     free (crypttest);
  978.     crypttest = NULL;
  979.     x = msgcryptok ();
  980.     if (x != SCMOK)
  981.         goaway ("Error sending encryption test reply to client");
  982. }
  983.  
  984. /***************************************************************
  985.  ***    C O N N E C T   T O   P R O P E R   A C C O U N T    ***
  986.  ***************************************************************/
  987.  
  988. login ()
  989. {
  990.     char *changeuid ();
  991.     register int x,fileuid,filegid;
  992.  
  993.     (void) netcrypt (PSWDCRYPT);    /* encrypt acct name and password */
  994.     x = msglogin ();
  995.     (void) netcrypt ((char *)NULL); /* turn off encryption */
  996.     if (x != SCMOK)  goaway ("Error reading login request from client");
  997.     if ( logcrypt ) {
  998.         if (strcmp(logcrypt,CRYPTTEST) != 0) {
  999.         logack = FLOGNG;
  1000.         logerror = "Improper login encryption";
  1001.         (void) msglogack ();
  1002.         goaway ("Client not encrypting login information properly");
  1003.         }
  1004.         free (logcrypt);
  1005.         logcrypt = NULL;
  1006.     }
  1007.     if (loguser == NULL) {
  1008.         if (cryptkey) {
  1009.             if (runas_uid >= 0 && runas_gid >= 0) {
  1010.                 fileuid = runas_uid;
  1011.                 filegid = runas_gid;
  1012.                 loguser = NULL;
  1013.             } else
  1014.                 loguser = salloc (DEFUSER);
  1015.         } else
  1016.             loguser = salloc (DEFUSER);
  1017.     }
  1018.     if ((logerror = changeuid (loguser,logpswd,fileuid,filegid)) != NULL) {
  1019.         logack = FLOGNG;
  1020.         (void) msglogack ();
  1021.         if (protver >= 6)  longjmp (sjbuf,TRUE);
  1022.         goaway ("Client denied login access");
  1023.     }
  1024.     if (loguser)  free (loguser);
  1025.     if (logpswd)  free (logpswd);
  1026.     logack = FLOGOK;
  1027.     x = msglogack ();
  1028.     if (x != SCMOK)  goaway ("Error sending login reply to client");
  1029.     if (!xpatch)  /* restore desired encryption */
  1030.         if (netcrypt (cryptkey) != SCMOK)
  1031.             goaway("Running non-crypting supfilesrv");
  1032.     free (cryptkey);
  1033.     cryptkey = NULL;
  1034. }
  1035.  
  1036. /*****************************************
  1037.  ***    M A K E   N A M E   L I S T    ***
  1038.  *****************************************/
  1039.  
  1040. listfiles ()
  1041. {
  1042.     int denyone();
  1043.     register int x;
  1044.  
  1045.     refuseT = NULL;
  1046.     x = msgrefuse ();
  1047.     if (x != SCMOK)  goaway ("Error reading refuse list from client");
  1048.     getscanlists ();
  1049.     Tfree (&refuseT);
  1050.     x = msglist ();
  1051.     if (x != SCMOK)  goaway ("Error sending file list to client");
  1052.     Tfree (&listT);
  1053.     listT = NULL;
  1054.     needT = NULL;
  1055.     x = msgneed ();
  1056.     if (x != SCMOK)
  1057.         goaway ("Error reading needed files list from client");
  1058.     denyT = NULL;
  1059.     (void) Tprocess (needT,denyone);
  1060.     Tfree (&needT);
  1061.     x = msgdeny ();
  1062.     if (x != SCMOK)  goaway ("Error sending denied files list to client");
  1063.     Tfree (&denyT);
  1064. }
  1065.  
  1066. denyone (t)
  1067. register TREE *t;
  1068. {
  1069.     register TREELIST *tl;
  1070.     register char *name = t->Tname;
  1071.     register int update = (t->Tflags&FUPDATE) != 0;
  1072.     struct stat sbuf;
  1073.     register TREE *tlink;
  1074.     TREE *linkcheck ();
  1075.     char slinkname[STRINGLENGTH];
  1076.     register int x;
  1077.  
  1078.     for (tl = listTL; tl != NULL; tl = tl->TLnext)
  1079.         if ((t = Tsearch (tl->TLtree,name)) != NULL)
  1080.             break;
  1081.     if (t == NULL) {
  1082.         (void) Tinsert (&denyT,name,FALSE);
  1083.         return (SCMOK);
  1084.     }
  1085.     cdprefix (tl->TLprefix);
  1086.     if ((t->Tmode&S_IFMT) == S_IFLNK)
  1087.         x = lstat(name,&sbuf);
  1088.     else
  1089.         x = stat(name,&sbuf);
  1090.     if (x < 0 || (sbuf.st_mode&S_IFMT) != (t->Tmode&S_IFMT)) {
  1091.         (void) Tinsert (&denyT,name,FALSE);
  1092.         return (SCMOK);
  1093.     }
  1094.     switch (t->Tmode&S_IFMT) {
  1095.     case S_IFLNK:
  1096.         if ((x = readlink (name,slinkname,STRINGLENGTH)) <= 0) {
  1097.             (void) Tinsert (&denyT,name,FALSE);
  1098.             return (SCMOK);
  1099.         }
  1100.         slinkname[x] = '\0';
  1101.         (void) Tinsert (&t->Tlink,slinkname,FALSE);
  1102.         break;
  1103.     case S_IFREG:
  1104.         if (sbuf.st_nlink > 1 &&
  1105.             (tlink = linkcheck (t,(int)sbuf.st_dev,(int)sbuf.st_ino)))
  1106.         {
  1107.             (void) Tinsert (&tlink->Tlink,name,FALSE);
  1108.             return (SCMOK);
  1109.         }
  1110.         if (update)  t->Tflags |= FUPDATE;
  1111.     case S_IFDIR:
  1112.         t->Tuid = sbuf.st_uid;
  1113.         t->Tgid = sbuf.st_gid;
  1114.         break;
  1115.     default:
  1116.         (void) Tinsert (&denyT,name,FALSE);
  1117.         return (SCMOK);
  1118.     }
  1119.     t->Tflags |= FNEEDED;
  1120.     return (SCMOK);
  1121. }
  1122.  
  1123. /*********************************
  1124.  ***    S E N D   F I L E S    ***
  1125.  *********************************/
  1126.  
  1127. sendfiles ()
  1128. {
  1129.     int sendone(),senddir(),sendfile();
  1130.     register TREELIST *tl;
  1131.     register int x;
  1132.  
  1133.     /* Does the protocol support compression */
  1134.     if (cancompress) {
  1135.         /* Check for compression on sending files */
  1136.         x = msgcompress();
  1137.         if ( x != SCMOK)
  1138.             goaway ("Error sending compression check to server");
  1139.     }
  1140.     /* send all files */
  1141.     for (tl = listTL; tl != NULL; tl = tl->TLnext) {
  1142.         cdprefix (tl->TLprefix);
  1143. #ifdef CVS
  1144.                 if (candorcs) {
  1145.                         cvs_root = getcwd(NULL, 256);
  1146.                         if (access("CVSROOT", F_OK) < 0)
  1147.                                 dorcs = FALSE;
  1148.                         else {
  1149.                                 loginfo("is a CVSROOT \"%s\"\n", cvs_root);
  1150.                                 dorcs = TRUE;
  1151.                         }
  1152.                 }
  1153. #endif
  1154.         (void) Tprocess (tl->TLtree,sendone);
  1155.     }
  1156.     /* send directories in reverse order */
  1157.     for (tl = listTL; tl != NULL; tl = tl->TLnext) {
  1158.         cdprefix (tl->TLprefix);
  1159.         (void) Trprocess (tl->TLtree,senddir);
  1160.     }
  1161.     x = msgsend ();
  1162.     if (x != SCMOK)
  1163.         goaway ("Error reading receive file request from client");
  1164.     upgradeT = NULL;
  1165.     x = msgrecv (sendfile,0);
  1166.     if (x != SCMOK)
  1167.         goaway ("Error sending file to client");
  1168. }
  1169.  
  1170. sendone (t)
  1171. TREE *t;
  1172. {
  1173.     register int x,fd;
  1174.     register int fdtmp;
  1175.     char sys_com[STRINGLENGTH], temp_file[STRINGLENGTH], rcs_file[STRINGLENGTH];
  1176.         union wait status;
  1177.     char *uconvert(),*gconvert();
  1178.     int sendfile ();
  1179.  
  1180.     if ((t->Tflags&FNEEDED) == 0)    /* only send needed files */
  1181.         return (SCMOK);
  1182.     if ((t->Tmode&S_IFMT) == S_IFDIR) /* send no directories this pass */
  1183.         return (SCMOK);
  1184.     x = msgsend ();
  1185.     if (x != SCMOK)  goaway ("Error reading receive file request from client");
  1186.     upgradeT = t;            /* upgrade file pointer */
  1187.     fd = -1;            /* no open file */
  1188.     if ((t->Tmode&S_IFMT) == S_IFREG) {
  1189.         if (!listonly && (t->Tflags&FUPDATE) == 0) {
  1190. #ifdef RCS
  1191.                         if (dorcs) {
  1192.                                 char rcs_release[STRINGLENGTH];
  1193.  
  1194.                 tmpnam(rcs_file);
  1195.                                 if (strcmp(&t->Tname[strlen(t->Tname)-2], ",v") == 0) {
  1196.                                         t->Tname[strlen(t->Tname)-2] = '\0';
  1197.                                         if (rcs_branch != NULL)
  1198. #ifdef CVS
  1199.                                                 sprintf(rcs_release, "-r %s", rcs_branch);
  1200. #else
  1201.                                                 sprintf(rcs_release, "-r%s", rcs_branch);
  1202. #endif
  1203.                                         else
  1204.                                                 rcs_release[0] = '\0';
  1205. #ifdef CVS
  1206.                                         sprintf(sys_com, "cvs -d %s -r -l -Q co -p %s %s > %s\n", cvs_root, rcs_release, t->Tname, rcs_file);
  1207. #else
  1208.                                         sprintf(sys_com, "co -q -p %s %s > %s 2> /dev/null\n", rcs_release, t->Tname, rcs_file);
  1209. #endif
  1210.                                         /*loginfo("using rcs mode \"%s\"\n", sys_com);*/
  1211.                                         status.w_status = system(sys_com);
  1212.                                         if (status.w_status < 0 || status.w_retcode) {
  1213.                                                 /* Just in case */
  1214.                                                 unlink(rcs_file);
  1215.                                                 if (status.w_status < 0) {
  1216.                                                         goaway ("We died trying to \"%s\"", sys_com);
  1217.                                                         t->Tmode = 0;
  1218.                                                 }
  1219.                                                 else {
  1220.                                                         /*logerr("rcs command failed \"%s\" = %d\n",
  1221.                                                                sys_com, status.w_retcode);*/
  1222.                                                         t->Tflags |= FUPDATE;
  1223.                                                 }
  1224.                                         }
  1225.                                         else if (docompress) {
  1226.                                                 tmpnam(temp_file);
  1227.                                                 sprintf(sys_com, "gzip -c < %s > %s\n", rcs_file, temp_file);
  1228.                                                 if (system(sys_com) < 0) {
  1229.                                                         /* Just in case */
  1230.                                                         unlink(temp_file);
  1231.                                                         unlink(rcs_file);
  1232.                                                         goaway ("We died trying to \"%s\"", sys_com);
  1233.                                                         t->Tmode = 0;
  1234.                                                 }
  1235.                                                 fd = open (temp_file,O_RDONLY,0);
  1236.                                         }
  1237.                                         else
  1238.                                                 fd = open (rcs_file,O_RDONLY,0);
  1239.                                 }
  1240.                         }
  1241. #endif
  1242.                         if (fd == -1) {
  1243.                                 if (docompress) {
  1244.                                         tmpnam(temp_file);
  1245.                                         sprintf(sys_com, "gzip -c < %s > %s\n", t->Tname, temp_file);
  1246.                                         if (system(sys_com) < 0) {
  1247.                                                 /* Just in case */
  1248.                                                 unlink(temp_file);
  1249.                                                 goaway ("We died trying to \"%s\"", sys_com);
  1250.                                                 t->Tmode = 0;
  1251.                                         }
  1252.                                         fd = open (temp_file,O_RDONLY,0);
  1253.                                 }
  1254.                                 else
  1255.                                         fd = open (t->Tname,O_RDONLY,0);
  1256.                         }
  1257.             if (fd < 0 && (t->Tflags&FUPDATE) == 0)  t->Tmode = 0;
  1258.         }
  1259.         if (t->Tmode) {
  1260.             t->Tuser = salloc (uconvert (t->Tuid));
  1261.             t->Tgroup = salloc (gconvert (t->Tgid));
  1262.         }
  1263.     }
  1264.     x = msgrecv (sendfile,fd);
  1265.     if (docompress)
  1266.         unlink(temp_file);
  1267. #ifdef RCS
  1268.     if (dorcs)
  1269.         unlink(rcs_file);
  1270. #endif
  1271.     if (x != SCMOK)  goaway ("Error sending file to client");
  1272.     return (SCMOK);
  1273. }
  1274.  
  1275. senddir (t)
  1276. TREE *t;
  1277. {
  1278.     register int x;
  1279.     char *uconvert(),*gconvert();
  1280.     int sendfile ();
  1281.  
  1282.     if ((t->Tflags&FNEEDED) == 0)    /* only send needed files */
  1283.         return (SCMOK);
  1284.     if ((t->Tmode&S_IFMT) != S_IFDIR) /* send only directories this pass */
  1285.         return (SCMOK);
  1286.     x = msgsend ();
  1287.     if (x != SCMOK)  goaway ("Error reading receive file request from client");
  1288.     upgradeT = t;            /* upgrade file pointer */
  1289.     t->Tuser = salloc (uconvert (t->Tuid));
  1290.     t->Tgroup = salloc (gconvert (t->Tgid));
  1291.     x = msgrecv (sendfile,0);
  1292.     if (x != SCMOK)  goaway ("Error sending file to client");
  1293.     return (SCMOK);
  1294. }
  1295.  
  1296. sendfile (t,ap)
  1297. register TREE *t;
  1298. va_list ap;
  1299. {
  1300.     register int x;
  1301.     int fd = va_arg(ap,int);
  1302.     if ((t->Tmode&S_IFMT) != S_IFREG || listonly || (t->Tflags&FUPDATE))
  1303.         return (SCMOK);
  1304.     x = writefile (fd);
  1305.     if (x != SCMOK)  goaway ("Error sending file to client");
  1306.         (void) close (fd);
  1307.     return (SCMOK);
  1308. }
  1309.  
  1310. /*****************************************
  1311.  ***    E N D   C O N N E C T I O N    ***
  1312.  *****************************************/
  1313.  
  1314. finishup (starttime)
  1315. long starttime;
  1316. {
  1317.     register int x = SCMOK;
  1318.     char tmpbuf[BUFSIZ], *p, lognam[STRINGLENGTH];
  1319.     int logfd;
  1320.     struct stat sbuf;
  1321.     long finishtime;
  1322.     char *releasename;
  1323.  
  1324.     (void) netcrypt ((char *)NULL);
  1325.     if (protver < 6) {
  1326.         if (goawayreason != NULL)
  1327.             free (goawayreason);
  1328.         goawayreason = (char *)NULL;
  1329.         x = msggoaway();
  1330.         doneack = FDONESUCCESS;
  1331.         donereason = salloc ("Unknown");
  1332.     } else if (goawayreason == (char *)NULL)
  1333.         x = msgdone ();
  1334.     else {
  1335.         doneack = FDONEGOAWAY;
  1336.         donereason = goawayreason;
  1337.     }
  1338.     if (x == SCMEOF || x == SCMERR) {
  1339.         doneack = FDONEUSRERROR;
  1340.         donereason = salloc ("Premature EOF on network");
  1341.     } else if (x != SCMOK) {
  1342.         doneack = FDONESRVERROR;
  1343.         donereason = salloc ("Unknown SCM code");
  1344.     }
  1345.     if (doneack == FDONEDONTLOG)
  1346.         return;
  1347.     if (donereason == NULL)
  1348.         donereason = salloc ("No reason");
  1349.     if (doneack == FDONESRVERROR || doneack == FDONEUSRERROR)
  1350.         logerr ("%s", donereason);
  1351.     else if (doneack == FDONEGOAWAY)
  1352.         logerr ("GOAWAY: %s",donereason);
  1353.     else if (doneack != FDONESUCCESS)
  1354.         logerr ("Reason %d:  %s",doneack,donereason);
  1355.     goawayreason = donereason;
  1356.     cdprefix ((char *)NULL);
  1357.     (void) sprintf (lognam,FILELOGFILE,collname);
  1358.     if ((logfd = open(lognam,O_APPEND|O_WRONLY,0644)) < 0)
  1359.         return; /* can not open file up...error */
  1360.     finishtime = time ((long *)NULL);
  1361.     p = tmpbuf;
  1362.     (void) sprintf (p,"%s ",fmttime (lasttime));
  1363.     p += strlen(p);
  1364.     (void) sprintf (p,"%s ",fmttime (starttime));
  1365.     p += strlen(p);
  1366.     (void) sprintf (p,"%s ",fmttime (finishtime));
  1367.     p += strlen(p);
  1368.     if ((releasename = release) == NULL)
  1369.         releasename = "UNKNOWN";
  1370.     (void) sprintf (p,"%s %s %d %s\n",remotehost(),releasename,
  1371.         FDONESUCCESS-doneack,donereason);
  1372.     p += strlen(p);
  1373. #if    MACH
  1374.     /* if we are busy dont get stuck updating the disk if full */
  1375.     if(setupack == FSETUPBUSY) {
  1376.         long l = FIOCNOSPC_ERROR;
  1377.         ioctl(logfd, FIOCNOSPC, &l);
  1378.     }
  1379. #endif    /* MACH */
  1380.     (void) write(logfd,tmpbuf,(p - tmpbuf));
  1381.     (void) close(logfd);
  1382. }
  1383.  
  1384. /***************************************************
  1385.  ***    H A S H   T A B L E   R O U T I N E S    ***
  1386.  ***************************************************/
  1387.  
  1388. Hfree (table)
  1389. HASH **table;
  1390. {
  1391.     register HASH *h;
  1392.     register int i;
  1393.     for (i = 0; i < HASHSIZE; i++)
  1394.         while (h = table[i]) {
  1395.             table[i] = h->Hnext;
  1396.             if (h->Hname)  free (h->Hname);
  1397.             free ((char *)h);
  1398.         }
  1399. }
  1400.  
  1401. HASH *Hlookup (table,num1,num2)
  1402. HASH **table;
  1403. int num1,num2;
  1404. {
  1405.     register HASH *h;
  1406.     register int hno;
  1407.     hno = HASHFUNC(num1,num2);
  1408.     for (h = table[hno]; h && (h->Hnum1 != num1 || h->Hnum2 != num2); h = h->Hnext);
  1409.     return (h);
  1410. }
  1411.  
  1412. Hinsert (table,num1,num2,name,tree)
  1413. HASH **table;
  1414. int num1,num2;
  1415. char *name;
  1416. TREE *tree;
  1417. {
  1418.     register HASH *h;
  1419.     register int hno;
  1420.     hno = HASHFUNC(num1,num2);
  1421.     h = (HASH *) malloc (sizeof(HASH));
  1422.     h->Hnum1 = num1;
  1423.     h->Hnum2 = num2;
  1424.     h->Hname = name;
  1425.     h->Htree = tree;
  1426.     h->Hnext = table[hno];
  1427.     table[hno] = h;
  1428. }
  1429.  
  1430. /*********************************************
  1431.  ***    U T I L I T Y   R O U T I N E S    ***
  1432.  *********************************************/
  1433.  
  1434. TREE *linkcheck (t,d,i)
  1435. TREE *t;
  1436. int d,i;            /* inode # and device # */
  1437. {
  1438.     register HASH *h;
  1439.     h = Hlookup (inodeH,i,d);
  1440.     if (h)  return (h->Htree);
  1441.     Hinsert (inodeH,i,d,(char *)NULL,t);
  1442.     return ((TREE *)NULL);
  1443. }
  1444.  
  1445. char *uconvert (uid)
  1446. int uid;
  1447. {
  1448.     register struct passwd *pw;
  1449.     register char *p;
  1450.     register HASH *u;
  1451.     u = Hlookup (uidH,uid,0);
  1452.     if (u)  return (u->Hname);
  1453.     pw = getpwuid (uid);
  1454.     if (pw == NULL)  return ("");
  1455.     p = salloc (pw->pw_name);
  1456.     Hinsert (uidH,uid,0,p,(TREE*)NULL);
  1457.     return (p);
  1458. }
  1459.  
  1460. char *gconvert (gid)
  1461. int gid;
  1462. {
  1463.     register struct group *gr;
  1464.     register char *p;
  1465.     register HASH *g;
  1466.     g = Hlookup (gidH,gid,0);
  1467.     if (g)  return (g->Hname);
  1468.     gr = getgrgid (gid);
  1469.     if (gr == NULL)  return ("");
  1470.     p = salloc (gr->gr_name);
  1471.     Hinsert (gidH,gid,0,p,(TREE *)NULL);
  1472.     return (p);
  1473. }
  1474.  
  1475. char *changeuid (namep,passwordp,fileuid,filegid)
  1476. char *namep,*passwordp;
  1477. int fileuid,filegid;
  1478. {
  1479.     char *okpassword ();
  1480.     char *group,*account,*pswdp;
  1481.     struct passwd *pwd;
  1482.     struct group *grp;
  1483. #if    CMUCS
  1484.     struct account *acc;
  1485.     struct ttyloc tlc;
  1486. #endif    /* CMUCS */
  1487.     register int status = ACCESS_CODE_OK;
  1488.     char nbuf[STRINGLENGTH];
  1489.     static char errbuf[STRINGLENGTH];
  1490. #if    CMUCS
  1491.     int *grps;
  1492. #endif    /* CMUCS */
  1493.     char *p;
  1494.  
  1495.     if (namep == NULL) {
  1496.         pwd = getpwuid (fileuid);
  1497.         if (pwd == NULL) {
  1498.             (void) sprintf (errbuf,"Reason:  Unknown user id %d",
  1499.                 fileuid);
  1500.             return (errbuf);
  1501.         }
  1502.         grp = getgrgid (filegid);
  1503.         if (grp)  group = strcpy (nbuf,grp->gr_name);
  1504.         else  group = NULL;
  1505.         account = NULL;
  1506.         pswdp = NULL;
  1507.     } else {
  1508.         (void) strcpy (nbuf,namep);
  1509.         account = group = index (nbuf,',');
  1510.         if (group != NULL) {
  1511.             *group++ = '\0';
  1512.             account = index (group,',');
  1513.             if (account != NULL) {
  1514.                 *account++ = '\0';
  1515.                 if (*account == '\0')  account = NULL;
  1516.             }
  1517.             if (*group == '\0')  group = NULL;
  1518.         }
  1519.         pwd = getpwnam (nbuf);
  1520.         if (pwd == NULL) {
  1521.             (void) sprintf (errbuf,"Reason:  Unknown user %s",
  1522.                 nbuf);
  1523.             return (errbuf);
  1524.         }
  1525.         if (strcmp (nbuf,DEFUSER) == 0)
  1526.             pswdp = NULL;
  1527.         else
  1528.             pswdp = passwordp ? passwordp : "";
  1529. #ifdef AFS
  1530.                 if (strcmp (nbuf,DEFUSER) != 0) {
  1531.                         char *reason;
  1532.                         setpag(); /* set a pag */
  1533.                         if (ka_UserAuthenticate(pwd->pw_name, "", 0,
  1534.                                                 pswdp, 1, &reason)) {
  1535.                                 (void) sprintf (errbuf,"AFS authentication failed, %s",
  1536.                                                 reason);
  1537.                                 logerr ("Attempt by %s; %s",
  1538.                                         nbuf, errbuf);
  1539.                                 return (errbuf);
  1540.                         }
  1541.                 }
  1542. #endif
  1543.     }
  1544.     if (getuid () != 0) {
  1545.         if (getuid () == pwd->pw_uid)
  1546.             return (NULL);
  1547.         if (strcmp (pwd->pw_name,DEFUSER) == 0)
  1548.             return (NULL);
  1549.         logerr ("Fileserver not superuser");
  1550.         return ("Reason:  fileserver is not running privileged");
  1551.     }
  1552. #if    CMUCS
  1553.     tlc.tlc_hostid = TLC_UNKHOST;
  1554.     tlc.tlc_ttyid = TLC_UNKTTY;
  1555.     if (okaccess(pwd->pw_name,ACCESS_TYPE_SU,0,-1,tlc) != 1)
  1556.         status = ACCESS_CODE_DENIED;
  1557.     else {
  1558.         grp = NULL;
  1559.         acc = NULL;
  1560.         status = oklogin(pwd->pw_name,group,&account,pswdp,&pwd,&grp,&acc,&grps);
  1561.         if (status == ACCESS_CODE_OK) {
  1562.             if ((p = okpassword(pswdp,pwd->pw_name,pwd->pw_gecos)) != NULL)
  1563.                 status = ACCESS_CODE_INSECUREPWD;
  1564.         }
  1565.     }
  1566. #else    /* CMUCS */
  1567.     status = ACCESS_CODE_OK;
  1568.     if (namep && strcmp(pwd->pw_name, DEFUSER) != 0)
  1569.         if (strcmp(pwd->pw_passwd,(char *)crypt(pswdp,pwd->pw_passwd)))
  1570.             status = ACCESS_CODE_BADPASSWORD;
  1571. #endif    /* CMUCS */
  1572.     switch (status) {
  1573.     case ACCESS_CODE_OK:
  1574.         break;
  1575.     case ACCESS_CODE_BADPASSWORD:
  1576.         p = "Reason:  Invalid password";
  1577.         break;
  1578. #if    CMUCS
  1579.     case ACCESS_CODE_INSECUREPWD:
  1580.         (void) sprintf (errbuf,"Reason:  %s",p);
  1581.         p = errbuf;
  1582.         break;
  1583.     case ACCESS_CODE_DENIED:
  1584.         p = "Reason:  Access denied";
  1585.         break;
  1586.     case ACCESS_CODE_NOUSER:
  1587.         p = errbuf;
  1588.         break;
  1589.     case ACCESS_CODE_ACCEXPIRED:
  1590.         p = "Reason:  Account expired";
  1591.         break;
  1592.     case ACCESS_CODE_GRPEXPIRED:
  1593.         p = "Reason:  Group expired";
  1594.         break;
  1595.     case ACCESS_CODE_ACCNOTVALID:
  1596.         p = "Reason:  Invalid account";
  1597.         break;
  1598.     case ACCESS_CODE_MANYDEFACC:
  1599.         p = "Reason:  User has more than one default account";
  1600.         break;
  1601.     case ACCESS_CODE_NOACCFORGRP:
  1602.         p = "Reason:  No account for group";
  1603.         break;
  1604.     case ACCESS_CODE_NOGRPFORACC:
  1605.         p = "Reason:  No group for account";
  1606.         break;
  1607.     case ACCESS_CODE_NOGRPDEFACC:
  1608.         p = "Reason:  No group for default account";
  1609.         break;
  1610.     case ACCESS_CODE_NOTGRPMEMB:
  1611.         p = "Reason:  Not member of group";
  1612.         break;
  1613.     case ACCESS_CODE_NOTDEFMEMB:
  1614.         p = "Reason:  Not member of default group";
  1615.         break;
  1616.     case ACCESS_CODE_OOPS:
  1617.         p = "Reason:  Internal error";
  1618.         break;
  1619. #endif    /* CMUCS */
  1620.     default:
  1621.         (void) sprintf (p = errbuf,"Reason:  Status %d",status);
  1622.         break;
  1623.     }
  1624.     if (pwd == NULL)
  1625.         return (p);
  1626.     if (status != ACCESS_CODE_OK) {
  1627.         logerr ("Login failure for %s",pwd->pw_name);
  1628.         logerr ("%s",p);
  1629. #if    CMUCS
  1630.         logaccess (pwd->pw_name,ACCESS_TYPE_SUP,status,0,-1,tlc);
  1631. #endif    /* CMUCS */
  1632.         return (p);
  1633.     }
  1634. #if    CMUCS
  1635.     if (setgroups (grps[0], &grps[1]) < 0)
  1636.         logerr ("setgroups: %%m");
  1637.     if (setgid ((gid_t)grp->gr_gid) < 0)
  1638.         logerr ("setgid: %%m");
  1639.     if (setuid ((uid_t)pwd->pw_uid) < 0)
  1640.         logerr ("setuid: %%m");
  1641. #else   /* CMUCS */
  1642.     if (initgroups (pwd->pw_name,pwd->pw_gid) < 0)
  1643.         return("Error setting group list");
  1644.     if (setgid (pwd->pw_gid) < 0)
  1645.         logerr ("setgid: %%m");
  1646.     if (setuid (pwd->pw_uid) < 0)
  1647.         logerr ("setuid: %%m");
  1648. #endif    /* CMUCS */
  1649.     return (NULL);
  1650. }
  1651.  
  1652. #if __STDC__
  1653. void
  1654. goaway (char *fmt,...)
  1655. #else
  1656. /*VARARGS*//*ARGSUSED*/
  1657. goaway (va_alist)
  1658. va_dcl
  1659. #endif
  1660. {
  1661. #if !__STDC__
  1662.     register char *fmt;
  1663. #endif
  1664.     char buf[STRINGLENGTH];
  1665.     va_list ap;
  1666.  
  1667.     (void) netcrypt ((char *)NULL);
  1668. #if __STDC__
  1669.     va_start(ap,fmt);
  1670. #else
  1671.     va_start(ap);
  1672.     fmt = va_arg(ap,char *);
  1673. #endif
  1674.     vsnprintf(buf, sizeof(buf), fmt, ap);
  1675.     va_end(ap);
  1676.     goawayreason = salloc (buf);
  1677.     (void) msggoaway ();
  1678.     logerr ("%s",buf);
  1679.     longjmp (sjbuf,TRUE);
  1680. }
  1681.  
  1682. char *fmttime (time)
  1683. long time;
  1684. {
  1685.     static char buf[STRINGLENGTH];
  1686.     int len;
  1687.  
  1688.     (void) strcpy (buf,ctime (&time));
  1689.     len = strlen(buf+4)-6;
  1690.     (void) strncpy (buf,buf+4,len);
  1691.     buf[len] = '\0';
  1692.     return (buf);
  1693. }
  1694.  
  1695. /*
  1696.  * Determine whether the file referenced by the file descriptor 'handle' can
  1697.  * be trusted, namely is it a file resident in the local file system.
  1698.  *
  1699.  * The main method of operation is to perform operations on the file
  1700.  * descriptor so that an attempt to spoof the checks should fail, for
  1701.  * example renamimg the file from underneath us and/or changing where the
  1702.  * file lives from underneath us.
  1703.  *
  1704.  * returns: -1 for error, indicating that we can not tell
  1705.  *         0 for file is definately not local, or it is an RFS link
  1706.  *         1 for file is local and can be trusted
  1707.  *
  1708.  * Side effect: copies the stat information into the supplied buffer,
  1709.  * regardless of the type of file system the file resides.
  1710.  *
  1711.  * Currently, the cases that we try to distinguish are RFS, AFS, NFS and
  1712.  * UFS, where the latter is considered a trusted file.  We assume that the
  1713.  * caller has disabled link following and will detect an attempt to access
  1714.  * a file through an RFS link, except in the case the the last component is
  1715.  * an RFS link.  With link following disabled, the last component itself is
  1716.  * interpreted as a regular file if it is really an RFS link, so we
  1717.  * disallow the RFS link identified by group "symlink" and mode "IEXEC by
  1718.  * owner only". An AFS file is
  1719.  * detected by trying the VIOCIGETCELL ioctl, which is one of the few AFS
  1720.  * ioctls which operate on a file descriptor.  Note, this AFS ioctl is
  1721.  * implemented in the cache manager, so the decision does not involve a
  1722.  * query with the AFS file server.  An NFS file is detected by looking at
  1723.  * the major device number and seeing if it matches the known values for
  1724.  * MACH NSF/Sun OS 3.x or Sun OS 4.x.
  1725.  *
  1726.  * Having the fstatfs() system call would make this routine easier and
  1727.  * more reliable.
  1728.  *
  1729.  * Note, in order to make the checks simpler, the file referenced by the
  1730.  * file descriptor can not be a BSD style symlink.  Even with symlink
  1731.  * following of the last path component disabled, the attempt to open a
  1732.  * file which is a symlink will succeed, so we check for the BSD symlink
  1733.  * file type here.  Also, the link following on/off and RFS file types
  1734.  * are only relevant in a MACH environment. 
  1735.  */
  1736. #ifdef    AFS
  1737. #include <sys/viceioctl.h>
  1738. #endif
  1739.  
  1740. #define SYMLINK_GRP 64
  1741.  
  1742. int local_file(handle, sinfo)
  1743. int handle;
  1744. struct stat *sinfo;
  1745. {
  1746.     struct stat sb;
  1747. #ifdef    VIOCIGETCELL
  1748.     /*
  1749.      * dummies for the AFS ioctl
  1750.      */
  1751.     struct ViceIoctl vdata;
  1752.     char cellname[512];
  1753. #endif    /* VIOCIGETCELL */
  1754.  
  1755.     if (fstat(handle, &sb) < 0)
  1756.         return(-1);
  1757.     if (sinfo != NULL)
  1758.         *sinfo = sb;
  1759.  
  1760. #if    CMUCS
  1761.     /*
  1762.      * If the following test succeeds, then the file referenced by
  1763.      * 'handle' is actually an RFS link, so we will not trust it.
  1764.      * See <sys/inode.h>.
  1765.      */
  1766.     if (sb.st_gid == SYMLINK_GRP
  1767.         && (sb.st_mode & (S_IFMT|S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)))
  1768.             == (S_IFREG|S_IEXEC))
  1769.         return(0);
  1770. #endif    /* CMUCS */
  1771.  
  1772.     /*
  1773.      * Do not trust BSD style symlinks either.
  1774.      */
  1775.     if ((sb.st_mode & S_IFMT) == S_IFLNK)
  1776.         return(0);
  1777.  
  1778. #ifdef    VIOCIGETCELL
  1779.     /*
  1780.      * This is the VIOCIGETCELL ioctl, which takes an fd, not
  1781.      * a path name.  If it succeeds, then the file is in AFS.
  1782.      *
  1783.      * On failure, ENOTTY indicates that the file was not in
  1784.      * AFS; all other errors are pessimistically assumed to be
  1785.      * a temporary AFS error.
  1786.      */
  1787.     vdata.in_size = 0;
  1788.     vdata.out_size = sizeof(cellname);
  1789.     vdata.out = cellname;
  1790.     if (ioctl(handle, VIOCIGETCELL, (char *)&vdata) != -1)
  1791.         return(0);
  1792.     if (errno != ENOTTY)
  1793.         return(-1);
  1794. #endif    /* VIOCIGETCELL */
  1795.  
  1796.     /*
  1797.      * Verify the file is not in NFS.
  1798.      *
  1799.      * Our current implementation and Sun OS 3.x use major device
  1800.      * 255 for NFS files; Sun OS 4.x seems to use 130 (I have only
  1801.      * determined this empirically -- DLC).  Without a fstatfs()
  1802.      * system call, this will have to do for now.
  1803.      */
  1804.     if (major(sb.st_dev) == 255 || major(sb.st_dev) == 130)
  1805.         return(0);
  1806.  
  1807.     return(1);
  1808. }
  1809.  
  1810. /*
  1811.  * Companion routine for ensuring that a local file can be trusted.  Compare
  1812.  * various pieces of the stat information to make sure that the file can be
  1813.  * trusted.  Returns true for stat information which meets the criteria
  1814.  * for being trustworthy.  The main paranoia is to prevent a hard link to
  1815.  * a root owned file.  Since the link could be removed after the file is
  1816.  * opened, a simply fstat() can not be relied upon.  The two stat buffers
  1817.  * for comparison should come from a stat() on the file name and a following
  1818.  * fstat() on the open file.  Some of the following checks are also an
  1819.  * additional level of paranoia.  Also, this test will fail (correctly) if
  1820.  * either or both of the stat structures have all fields zeroed; typically
  1821.  * due to a stat() failure.
  1822.  */
  1823.  
  1824.  
  1825. int stat_info_ok(sb1, sb2)
  1826. struct stat *sb1, *sb2;
  1827. {
  1828.     return (sb1->st_ino == sb2->st_ino &&    /* Still the same file */
  1829.         sb1->st_dev == sb2->st_dev &&    /* On the same device */
  1830.         sb1->st_mode == sb2->st_mode &&     /* Perms (and type) same */
  1831.         (sb1->st_mode & S_IFMT) == S_IFREG && /* Only allow reg files */
  1832.         (sb1->st_mode & 077) == 0 &&    /* Owner only perms */
  1833.         sb1->st_nlink == sb2->st_nlink &&    /* # hard links same... */
  1834.         sb1->st_nlink == 1 &&        /* and only 1 */
  1835.         sb1->st_uid == sb2->st_uid &&    /* owner and ... */
  1836.         sb1->st_gid == sb2->st_gid &&    /* group unchanged */
  1837.         sb1->st_mtime == sb2->st_mtime &&    /* Unmodified between stats */
  1838.         sb1->st_ctime == sb2->st_ctime);    /* Inode unchanged.  Hopefully
  1839.                            a catch-all paranoid test */
  1840. }
  1841.  
  1842. #if MACH
  1843. /*
  1844.  * Twiddle symbolic/RFS link following on/off.  This is a no-op in a non
  1845.  * CMUCS/MACH environment.  Also, the setmodes/getmodes interface is used
  1846.  * mainly because it is simpler than using table(2) directly.
  1847.  */
  1848. #include <sys/table.h>
  1849.  
  1850. int link_nofollow(on)
  1851. int on;
  1852. {
  1853.     static int modes = -1;
  1854.  
  1855.     if (modes == -1 && (modes = getmodes()) == -1)
  1856.         return(-1);
  1857.     if (on)
  1858.         return(setmodes(modes | UMODE_NOFOLLOW));
  1859.     return(setmodes(modes));
  1860. }
  1861. #else    /* MACH */
  1862. /*ARGSUSED*/
  1863. int link_nofollow(on)
  1864. int on;
  1865. {
  1866.     return(0);
  1867. }
  1868. #endif    /* MACH */
  1869.